package cn.outsourcing.supermarket.common.utils;

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.Arrays;
import java.util.Optional;

/**
 * Aes 加密算法工具类
 *
 * @author gzkemays
 * @since 2021/10/21 10:57
 */
public class AesUtils {
  private AesUtils() {}

  private static final String ALGORITHM = "AES";
  private static final String CHARSET_NAME = "UTF-8";
  private static final String AES_CPK7 = "AES/CBC/PKCS7Padding";
  /**
   * 加密
   *
   * @param data - 加密数据
   * @return - 返回加密后的字符串
   */
  public static String encrypt(String data) throws GeneralSecurityException {
    return encrypt(data, null);
  }

  /**
   * 解密
   *
   * @param data - 加密字符串
   * @return - 解密字符串
   */
  public static String decrypt(String data) throws GeneralSecurityException {
    return decrypt(data, null);
  }

  /**
   * 根据key字符串加密
   *
   * @param data - 加密数据
   * @param key - 盐值
   * @return - 返回加密后的字符串
   */
  public static String encrypt(String data, String key) throws GeneralSecurityException {
    try {
      key = getSecretKey(key);
      Key k = toKey(Base64.decodeBase64(key));
      byte[] raw = k.getEncoded();
      SecretKeySpec secretKeySpec = new SecretKeySpec(raw, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(1, secretKeySpec);
      byte[] bytes = cipher.doFinal(data.getBytes(CHARSET_NAME));
      return Base64.encodeBase64String(bytes);
    } catch (UnsupportedEncodingException e) {
      // 不支持的编码异常
      return data;
    }
  }

  /**
   * 根据key解密字符串
   *
   * @param data - 加密字符串
   * @param key - 盐值
   * @return - 返回解密后的字符串
   */
  public static String decrypt(String data, String key) throws GeneralSecurityException {
    try {
      key = getSecretKey(key);
      Key k = toKey(Base64.decodeBase64(key));
      byte[] raw = k.getEncoded();
      SecretKeySpec secretKeySpec = new SecretKeySpec(raw, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(2, secretKeySpec);
      byte[] baseData = Base64.decodeBase64(data);
      if (baseData.length == 0) {
        throw new RuntimeException("数据无法通过Base64解码");
      }
      byte[] bytes = cipher.doFinal(baseData);
      return new String(bytes, CHARSET_NAME);
    } catch (UnsupportedEncodingException e) {
      // 不支持的编码异常
      return data;
    }
  }

  /**
   * 获取序列化密钥
   *
   * @param key 序列化字段
   * @return {@link Key}
   */
  private static Key toKey(byte[] key) {
    return new SecretKeySpec(key, ALGORITHM);
  }

  /**
   * 获取加密密钥
   *
   * @param encrypted 序列化密钥
   * @return 加密密钥结果
   */
  private static String getSecretKey(String encrypted) throws UnsupportedEncodingException {
    encrypted = Optional.ofNullable(encrypted).orElse(AesUtils.class.getName());
    byte[] bytes = encrypted.getBytes(CHARSET_NAME);
    bytes = Arrays.copyOf(bytes, 16);
    return Base64.encodeBase64String(bytes);
  }

  /**
   * 微信 Aes 解密
   *
   * @param content 密文
   * @return 解密字符串
   */
  public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)
      throws InvalidAlgorithmParameterException {
    try {
      // 加入 security 代理，否则找不到 PKCS7Padding 解密文件
      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
      Cipher cipher = Cipher.getInstance(AES_CPK7);
      Key sKeySpec = new SecretKeySpec(keyByte, ALGORITHM);
      // 生成iv
      AlgorithmParameters params = AlgorithmParameters.getInstance(ALGORITHM);
      params.init(new IvParameterSpec(ivByte));
      // 初始化
      cipher.init(Cipher.DECRYPT_MODE, sKeySpec, params);
      return cipher.doFinal(content);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
}
